import {
  Memory,
  MemoryType,
  MemoryRetrievalConfig,
  PromptBuildContext
} from './types';

/**
 * 记忆检索器
 * 负责智能检索和排序相关记忆
 */
export class MemoryRetriever {
  private config: MemoryRetrievalConfig;
  private memories: Memory[] = [];

  constructor(config?: MemoryRetrievalConfig) {
    this.config = config || this.getDefaultConfig();
  }

  /**
   * 添加记忆
   */
  addMemory(memory: Memory): void {
    this.memories.push(memory);
  }

  /**
   * 批量添加记忆
   */
  addMemories(memories: Memory[]): void {
    this.memories.push(...memories);
  }

  /**
   * 检索相关记忆
   */
  retrieveRelevantMemories(
    context: PromptBuildContext,
    query?: string
  ): Memory[] {
    const searchQuery = query || context.userMessage;
    
    // 计算相关性分数
    const scoredMemories = this.memories.map(memory => ({
      memory,
      score: this.calculateRelevanceScore(memory, searchQuery, context)
    }));

    // 过滤低分记忆
    const filteredMemories = scoredMemories.filter(
      item => item.score >= this.config.semanticThreshold
    );

    // 按分数排序
    const sortedMemories = filteredMemories.sort((a, b) => b.score - a.score);

    // 限制数量
    const limitedMemories = sortedMemories.slice(0, this.config.maxMemories);

    // 应用作用域过滤
    const scopeFilteredMemories = this.config.scopeFiltering
      ? this.applyScopeFiltering(limitedMemories.map(item => item.memory), context)
      : limitedMemories.map(item => item.memory);

    return scopeFilteredMemories;
  }

  /**
   * 计算相关性分数
   */
  private calculateRelevanceScore(
    memory: Memory,
    query: string,
    context: PromptBuildContext
  ): number {
    let score = 0;

    // 语义相似度 (简化实现，实际应使用向量相似度)
    score += this.calculateSemanticSimilarity(memory.content, query) * 0.4;

    // 类型权重
    score += this.getTypeWeight(memory.type) * 0.2;

    // 时间衰减
    if (this.config.timeDecayFactor > 0) {
      const timeScore = this.calculateTimeDecay(memory.timestamp);
      score += timeScore * 0.2;
    }

    // 上下文相关性
    score += this.calculateContextRelevance(memory, context) * 0.2;

    // 已有相关性分数
    if (memory.relevance !== undefined) {
      score += memory.relevance * 0.1;
    }

    return Math.min(score, 1.0);
  }

  /**
   * 计算语义相似度 (简化实现)
   */
  private calculateSemanticSimilarity(content: string, query: string): number {
    const contentWords = this.tokenize(content.toLowerCase());
    const queryWords = this.tokenize(query.toLowerCase());

    if (contentWords.length === 0 || queryWords.length === 0) {
      return 0;
    }

    // 计算词汇重叠度
    const intersection = contentWords.filter(word => queryWords.includes(word));
    const union = [...new Set([...contentWords, ...queryWords])];

    const jaccardSimilarity = intersection.length / union.length;

    // 计算TF-IDF相似度的简化版本
    const tfIdfSimilarity = this.calculateTfIdfSimilarity(contentWords, queryWords);

    // 组合相似度分数
    return (jaccardSimilarity * 0.6 + tfIdfSimilarity * 0.4);
  }

  /**
   * 分词
   */
  private tokenize(text: string): string[] {
    return text
      .replace(/[^\w\s]/g, ' ')
      .split(/\s+/)
      .filter(word => word.length > 2)
      .filter(word => !this.isStopWord(word));
  }

  /**
   * 检查是否为停用词
   */
  private isStopWord(word: string): boolean {
    const stopWords = new Set([
      'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for',
      'of', 'with', 'by', 'is', 'are', 'was', 'were', 'be', 'been', 'have',
      'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could', 'should',
      'this', 'that', 'these', 'those', 'i', 'you', 'he', 'she', 'it', 'we', 'they'
    ]);
    return stopWords.has(word.toLowerCase());
  }

  /**
   * 计算TF-IDF相似度的简化版本
   */
  private calculateTfIdfSimilarity(contentWords: string[], queryWords: string[]): number {
    const contentFreq = this.calculateTermFrequency(contentWords);
    const queryFreq = this.calculateTermFrequency(queryWords);

    let dotProduct = 0;
    let contentMagnitude = 0;
    let queryMagnitude = 0;

    const allTerms = new Set([...Object.keys(contentFreq), ...Object.keys(queryFreq)]);

    for (const term of allTerms) {
      const contentTf = contentFreq[term] || 0;
      const queryTf = queryFreq[term] || 0;

      dotProduct += contentTf * queryTf;
      contentMagnitude += contentTf * contentTf;
      queryMagnitude += queryTf * queryTf;
    }

    if (contentMagnitude === 0 || queryMagnitude === 0) {
      return 0;
    }

    return dotProduct / (Math.sqrt(contentMagnitude) * Math.sqrt(queryMagnitude));
  }

  /**
   * 计算词频
   */
  private calculateTermFrequency(words: string[]): Record<string, number> {
    const freq: Record<string, number> = {};
    for (const word of words) {
      freq[word] = (freq[word] || 0) + 1;
    }
    
    // 归一化
    const maxFreq = Math.max(...Object.values(freq));
    for (const word in freq) {
      freq[word] = freq[word] / maxFreq;
    }
    
    return freq;
  }

  /**
   * 获取类型权重
   */
  private getTypeWeight(type: MemoryType): number {
    const weights = {
      [MemoryType.INSTRUCTION]: 0.9,
      [MemoryType.PREFERENCE]: 0.8,
      [MemoryType.PATTERN]: 0.7,
      [MemoryType.CONTEXT]: 0.6,
      [MemoryType.FACT]: 0.5
    };
    return weights[type] || 0.5;
  }

  /**
   * 计算时间衰减
   */
  private calculateTimeDecay(timestamp: Date): number {
    const now = new Date();
    const ageInDays = (now.getTime() - timestamp.getTime()) / (1000 * 60 * 60 * 24);
    
    // 指数衰减函数
    return Math.exp(-ageInDays * this.config.timeDecayFactor);
  }

  /**
   * 计算上下文相关性
   */
  private calculateContextRelevance(
    memory: Memory,
    context: PromptBuildContext
  ): number {
    let relevance = 0;

    // 检查与当前代码上下文的相关性
    if (context.codeContext && memory.metadata?.codeContext) {
      if (context.codeContext.currentFile?.path === memory.metadata.codeContext.filePath) {
        relevance += 0.5;
      }
      
      if (context.codeContext.gitInfo?.branch === memory.metadata.codeContext.branch) {
        relevance += 0.2;
      }
    }

    // 检查与聊天模式的相关性
    if (memory.metadata?.chatMode === context.mode) {
      relevance += 0.3;
    }

    return Math.min(relevance, 1.0);
  }

  /**
   * 应用作用域过滤
   */
  private applyScopeFiltering(
    memories: Memory[],
    context: PromptBuildContext
  ): Memory[] {
    return memories.filter(memory => {
      // 检查作用域匹配
      if (memory.metadata?.scope) {
        switch (memory.metadata.scope) {
          case 'global':
            return true;
          case 'workspace':
            return context.codeContext?.workspaceFiles !== undefined;
          case 'project':
            return context.codeContext?.currentFile !== undefined;
          default:
            return true;
        }
      }
      return true;
    });
  }

  /**
   * 更新记忆相关性
   */
  updateMemoryRelevance(memoryId: string, relevance: number): void {
    const memory = this.memories.find(m => m.id === memoryId);
    if (memory) {
      memory.relevance = relevance;
    }
  }

  /**
   * 删除记忆
   */
  removeMemory(memoryId: string): boolean {
    const index = this.memories.findIndex(m => m.id === memoryId);
    if (index !== -1) {
      this.memories.splice(index, 1);
      return true;
    }
    return false;
  }

  /**
   * 清空记忆
   */
  clearMemories(): void {
    this.memories = [];
  }

  /**
   * 获取所有记忆
   */
  getAllMemories(): Memory[] {
    return [...this.memories];
  }

  /**
   * 获取记忆统计
   */
  getMemoryStats(): {
    total: number;
    byType: Record<MemoryType, number>;
    averageRelevance: number;
  } {
    const byType = {} as Record<MemoryType, number>;
    let totalRelevance = 0;
    let relevanceCount = 0;

    for (const memory of this.memories) {
      byType[memory.type] = (byType[memory.type] || 0) + 1;
      
      if (memory.relevance !== undefined) {
        totalRelevance += memory.relevance;
        relevanceCount++;
      }
    }

    return {
      total: this.memories.length,
      byType,
      averageRelevance: relevanceCount > 0 ? totalRelevance / relevanceCount : 0
    };
  }

  /**
   * 获取默认配置
   */
  private getDefaultConfig(): MemoryRetrievalConfig {
    return {
      maxMemories: 10,
      semanticThreshold: 0.3,
      timeDecayFactor: 0.01,
      scopeFiltering: true,
      relevanceScoring: true
    };
  }
}
